package com.wctj.api.base.aspect;

import cn.hutool.json.JSONUtil;
import com.google.common.collect.Maps;
import com.wctj.api.base.dto.JwtUserDTO;
import com.wctj.api.base.utils.IPUtil;
import com.wctj.api.base.context.RequestContext;
import com.wctj.api.base.utils.JacksonUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Objects;

@Slf4j
@Aspect
@Component
public class LogPrintAspect {
    private static final Integer paramsTooLong = 500;

    private static final Integer resultTooLong = 500;

    private static final String REQUEST_MESSAGE_TEMPLATE = "请求模块：{}，请求方法名：{}，当前操作用户：{}，请求IP: {}，请求url: {}，调用类名: {}，调用方法名: {}，调用参数: {}";

    private static final String RESPONSE_MESSAGE_TEMPLATE = "请求模块：{}，请求方法名：{}，调用类名: {}，调用方法名: {}，请求耗时: {}，返回结果集：{}";

    @Around(value = "@within(io.swagger.annotations.Api)")
    public Object logPrint(ProceedingJoinPoint joinPoint) throws Throwable {
        // 记录开始时间
        long start = System.currentTimeMillis();
        // 返回值
        Object result = joinPoint.proceed();
        // 模块名
        String moduleName = null;
        // 方法名
        String methodName = null;
        try {
            // 当前登录用户
            JwtUserDTO currentUser = RequestContext.getCurrentUser();
            // 模块描述
            Class<?> targetObj = joinPoint.getTarget().getClass();
            Api api = targetObj.getAnnotation(Api.class);
            if (api != null && api.tags().length > 0) {
                moduleName = api.tags()[0];
            }

            Signature signature = joinPoint.getSignature();
            if (signature instanceof MethodSignature) {
                MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
                Method method = methodSignature.getMethod();
                // 方法描述
                ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
                if (apiOperation != null) {
                    methodName = apiOperation.value();
                }else {
                    methodName = method.getName();
                }
                // 参数名称
                String[] parameterNames = methodSignature.getParameterNames();
                // 参数值
                Object[] args = joinPoint.getArgs();
                // 获取请求对象
                HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
                /*log.debug(REQUEST_MESSAGE_TEMPLATE, moduleName, methodName, JSON.toJSONString(currentUser), IPUtil.getLocalIp(request), request.getRequestURL(),
                        targetObj.getName(), method.getName(), this.getParamLog(parameterNames, args));*/
                log.debug(REQUEST_MESSAGE_TEMPLATE, moduleName, methodName, JacksonUtil.getNormalPatternJsonString(currentUser), IPUtil.getLocalIp(request), request.getRequestURL(),
                        targetObj.getName(), method.getName(), this.getParamLog(parameterNames, args));
                log.debug(RESPONSE_MESSAGE_TEMPLATE, moduleName, methodName, targetObj.getName(), method.getName(), System.currentTimeMillis() - start, this.getResultLog(result));
            }
        } catch (Exception e) {
            log.error("拦截方法失败", e);
        }

        return result;
    }

    private String getParamLog(String[] parameterNames, Object[] args) {
        Map<String, Object> map = Maps.newHashMap();
        if (parameterNames != null && parameterNames.length > 0) {
            for (int i = 0; i < parameterNames.length; i++) {
                if (args[i] instanceof HttpServletRequest || args[i] instanceof HttpServletResponse) {
                    map.put(parameterNames[i], "HttpServletRequest HttpServletResponse不打印");
                } else {
                    map.put(parameterNames[i], args[i]);
                }
            }
        }
        String params = JSONUtil.toJsonStr(map);
        if (StringUtils.hasText(params) && params.length() > paramsTooLong) {
            return params.substring(0, 200).concat("...");
        }

        return params;
    }

    private String getResultLog(Object obj) {
        String result = JSONUtil.toJsonStr(obj);
        if (StringUtils.hasText(result) && result.length() > resultTooLong) {
            return result.substring(0, 200).concat("...");
        }

        return result;
    }
}